package com.redis.demo.controller;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @Author zqf
 * @Date 2022/10/28 16:28
 * @Description: 商城秒杀
 */

@RestController("/redisLock")
@Api(tags = "模拟商城秒杀")
public class    StoreSeckillController {

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    private final static String STORE = "store";
    private final static String LOCK = "lock";


    @GetMapping("setStore")
    @ApiOperation("设置库存")
    private String storeSeckill(@RequestParam("store") String store) {
        redisTemplate.opsForValue().set(STORE, store);
        return "设置成功";
    }

    @GetMapping("redisOrder")
    @ApiOperation("redis的set模拟下单减去库存")
    private String storeSeckill() {

        //设置uuid的意义在与防止释放锁的锁的时候释放成别人的锁
        String uuid = UUID.randomUUID().toString();

        //设置过期时间是为了防止该线程在执行中宕机从而导致锁释放不出去
        Boolean isLock = redisTemplate.opsForValue().setIfAbsent(LOCK, uuid, 5000, TimeUnit.MILLISECONDS);

        //设置成功了，证明抢到了锁
        if (isLock) {
            //先查询是否有库存
            try {
                Integer store = Integer.valueOf(Objects.requireNonNull(redisTemplate.opsForValue().get(STORE)));

                if (store > 0) {
                    //库存减1
                    redisTemplate.opsForValue().decrement(STORE);
                    return "抢购成功";
                }
                return "库存不足";

            } finally {
                //释放锁,这里获取是确认是自己的锁才释放
                if (Objects.equals(redisTemplate.opsForValue().get(LOCK), uuid)){
                    redisTemplate.delete(LOCK);
                }
            }
        }
        //如果未获取到锁,进入自旋
        storeSeckill();
        return "当前访问人数较多，请稍后访问";
    }
}
